import java.util.ArrayList;

public class DBManipulator {

	// Constructor
	public DBManipulator() {

	}

	// Get null-free subschema
	public ArrayList<String> getNullFreeSubSchema(ArrayList<String[]> list,
			int col, ArrayList<String> R) {
		ArrayList<String> nfs = new ArrayList<String>();
		boolean[] flag = new boolean[col];

		for (int i = 0; i < col; i++) {
			flag[i] = true;
		}

		// Checking null
		for (int i = 0; i < list.size(); i++) {
			for (int j = 0; j < col; j++) {
				if (flag[j]) {
					if (list.get(i)[j].equals("null")) {
						flag[j] = false;
					}
				}
			}
		}

		// If a column is total
		for (int i = 0; i < col; i++) {
			if (flag[i]) {
				nfs.add(R.get(i));
			}
		}

		return nfs;
	}

	// Detect available FDs
	public ArrayList<FuncDep> getFDs(ArrayList<String[]> table, int col,
			ArrayList<String> R) {
		ArrayList<FuncDep> FDs = new ArrayList<FuncDep>();
		ArrayList<ArrayList<Integer>> orders = new ArrayList<ArrayList<Integer>>();
		orders = getOrderList(col);

		ArrayList<ArrayList<String>> left = new ArrayList<ArrayList<String>>();
		ArrayList<String> right = new ArrayList<String>();

		// Check for each arrangement
		for (int i = 0; i < orders.size(); i++) {
			boolean fd_existed = false;

			// Check for the rhs of each attribute
			ArrayList<String> temp = new ArrayList<String>();

			for (int k = 0; k < table.size(); k++) {
				for (int j = 0; j < col; j++) {
					if (orders.get(i).contains(j)) {
						temp.add(table.get(k)[j]);
					}
				}
			}
		}

		// Check for Single FD for each column
		for (int i = 0; i < col; i++) {
			for (int j = 0; j < col; j++) {
				if (j != i) {
					ArrayList<String> left_list = new ArrayList<String>();
					ArrayList<String> right_list = new ArrayList<String>();
					boolean valid = true;

					for (int k = 0; k < table.size(); k++) {
						if (!table.get(k)[i].equals("null")) {
							String left = table.get(k)[i];
							int index = left_list.indexOf(left);

							if (index != -1) {
								String right = "null";

								if (!table.get(k)[j].equals("null")) {
									right = table.get(k)[j];
								}

								if (!right.equals(right_list.get(index))) {
									valid = false;
									break;
								}

							} else {
								left_list.add(table.get(k)[i]);
								if (!table.get(k)[j].equals("null")) {
									right_list.add(table.get(k)[j]);
								} else {
									right_list.add("null");
								}
							}
						}
					}

					if (valid) {
						FuncDep fd = new FuncDep(R.get(i), R.get(j));
						FDs.add(fd);
					}
				}
			}
		}

		return FDs;
	}

	// Get all the arrangements of left hand side of FDs
	private ArrayList<ArrayList<Integer>> getOrderList(int col) {
		// Number of attributes on the left side
		ArrayList<ArrayList<Integer>> orders = new ArrayList<ArrayList<Integer>>();
		for (int i = 1; i <= col - 1; i++) {
			int max = (int) Math.pow(10, i);

			// Treating one case
			for (int j = 0; j < max; j++) {
				ArrayList<Integer> ord = new ArrayList<Integer>();
				boolean good = true;
				int num = j;
				for (int k = 0; k < i; k++) {
					int digit = num % 10;
					num /= 10;
					if (good) {
						if (digit >= col || ord.contains(digit)) {
							good = false;
						} else {
							ord.add(0, digit);
						}
					}
				}
				if (good) {
					if (!existed(orders, ord)) {
						orders.add(ord);
					}
				}
			}
		}

		return orders;
	}

	// Check for existed arrangement
	private boolean existed(ArrayList<ArrayList<Integer>> orders,
			ArrayList<Integer> ord) {
		for (int i = 0; i < orders.size(); i++) {
			if (orders.get(i).size() == ord.size()) {
				boolean dup = true;
				for (int j = 0; j < ord.size(); j++) {
					if (!orders.get(i).contains(ord.get(j))) {
						dup = false;
					}
				}
				if (dup) {
					return true;
				}
			}
		}
		return false;
	}
}
